package com.captjack.distributedlock.aspect;

import com.captjack.distributedlock.annotation.DistributedLockByZookeeper;
import com.captjack.distributedlock.lock.ZookeeperDistributedLock;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

import java.util.concurrent.TimeUnit;

/**
 * 开启zookeeper分布式锁切面
 *
 * @author Capt Jack
 * @date 2018/7/12
 */
@Configuration
@Aspect
@EnableAspectJAutoProxy(proxyTargetClass = true)
@ConditionalOnProperty(value = "distributed.lock.zookeeper.enable", havingValue = "true")
public class DistributedLockByZookeeperAspect extends BaseDistributedLock {

    /**
     * 日志
     */
    private static final Logger logger = LoggerFactory.getLogger(DistributedLockByZookeeperAspect.class);

    /**
     * zookeeper锁前缀
     */
    private static final String LOCK_PATH_PREFIX = "/captjack/distributed/lock/";

    /**
     * 分布式锁操作
     */
    private final ZookeeperDistributedLock zookeeperDistributedLock;

    /**
     * @param proceedingJoinPoint 切点信息
     * @return 执行信息
     */
    @Around(value = "@annotation(com.captjack.distributedlock.annotation.DistributedLockByZookeeper)")
    Object service(ProceedingJoinPoint proceedingJoinPoint) {
        Object result = null;
        // 是否获得锁
        boolean isLock = false;
        // 锁id
        String lockId = null;
        // 注解实例
        DistributedLockByZookeeper distributedLockByZookeeper;
        try {
            // 获取注解实例
            distributedLockByZookeeper = super.getAnnotation(proceedingJoinPoint, DistributedLockByZookeeper.class);
            // 获取锁id
            lockId = LOCK_PATH_PREFIX + distributedLockByZookeeper.lockId();
            // 获取锁
            isLock = zookeeperDistributedLock.acquire(lockId, distributedLockByZookeeper.waitLockTime(), distributedLockByZookeeper.waitLockTimeUnit(), distributedLockByZookeeper.isWaitLockUntilTimeOut());
            // 获取锁成功，执行操作，解锁标识设置为false
            if (isLock) {
                result = proceedingJoinPoint.proceed();
            }
        } catch (Throwable throwable) {
            logger.error("DistributedLockByZookeeperAspect error!", throwable);
        } finally {
            // 总是在最后释放锁
            if (isLock) {
                try {
                    do {
                        isLock = !zookeeperDistributedLock.release(lockId);
                    } while (isLock);
                } catch (Exception e) {
                    logger.error("DistributedLockByZookeeperAspect release lock error! ", e);
                }
            }
        }
        return result;
    }

    @Autowired
    public DistributedLockByZookeeperAspect(@Qualifier(value = "zookeeper_distributed_lock") ZookeeperDistributedLock zookeeperDistributedLock) {
        this.zookeeperDistributedLock = zookeeperDistributedLock;
    }

    public static void main(String[] args) {
        System.out.println(TimeUnit.MILLISECONDS.convert(-1, TimeUnit.MILLISECONDS));
    }

}
